package com.hxzy.controller.api.system;

import cn.hutool.core.codec.Base64;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.jwt.JWTUtil;
import com.hxzy.common.TZXMConst;
import com.hxzy.common.exception.ServerException;
import com.hxzy.common.util.BuildVueRouterUtil;
import com.hxzy.common.util.ThreadLocalUtil;
import com.hxzy.common.vo.CodeEnum;
import com.hxzy.common.vo.R;
import com.hxzy.dto.system.LoginDTO;
import com.hxzy.entity.system.SysUser;
import com.hxzy.service.system.SysMenuService;
import com.hxzy.vo.system.HxzyUser;
import com.hxzy.vo.system.MenuVO;
import com.hxzy.vo.system.menu.RouterVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Api(tags = "后台登录")
@RestController
@RequestMapping(value = "/api")
public class LoginController {

    @Value(value = "${token.jwtpwd}")
    private String jwtPwd;

    @Value(value = "${token.expired}")
    private Long tokenExpired;

    @Autowired
    private RedisTemplate redisTemplate;


    @Autowired
    private SysMenuService sysMenuService;
    @Autowired
    private BuildVueRouterUtil buildVueRouterUtil;

    /**
     * spring security自定义数据库认证的管理接口
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    @ApiOperation(value = "生成扫描登录二维码")
    @GetMapping(value = "/getQR")
    public R createQR() throws IOException {
        // 1、生成二维码
        // D:\qrcode.jpg 生成二维码的地址  (前端确认页面。前端确认按钮，获取token)
        BufferedImage generate = QrCodeUtil.generate("http://localhost:8080/api/loginQR", 300, 300);

        //将图片转换陈字符串给前端
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ImageIO.write(generate, "png", stream);

        String base64 = Base64.encode(stream.toByteArray());

        //转换成base64位字符串
        return R.success("data:image/png;base64,"+base64);
    }


    /**
     * 登录方法
     *
     * @param loginDTO 登录信息
     * @return 结果
     */
    @ApiOperation(value = "登录")
    @PostMapping("/login")
    public R login(@RequestBody @Valid LoginDTO loginDTO){
        //验证redis中的验证码是否过期
        String captchaRedisKey=TZXMConst.REDIS_CAPTCHA_KEY+loginDTO.getUuid();
        Object redisValue=this.redisTemplate.opsForValue().get(captchaRedisKey);

        if (Objects.isNull(redisValue)) {
            throw new ServerException(CodeEnum.ADMIN_CAPTCHA_EXPIRED);
        }

        //判断验证码对不对
        if(!loginDTO.getCode().equalsIgnoreCase(redisValue.toString())){
            //删除验证码缓存
            this.redisTemplate.delete(captchaRedisKey);

            throw new ServerException(CodeEnum.ADMIN_CAPTCHA_INCORRECT);
        }

        //删除验证码缓存
        this.redisTemplate.delete(captchaRedisKey);

        //springsecurity的登录的方式
        UsernamePasswordAuthenticationToken unath=new UsernamePasswordAuthenticationToken(loginDTO.getPhone(),loginDTO.getPassword());

        //通过spring security(登录)   UserDetailsService接口
        Authentication authenticate = this.authenticationManager.authenticate(unath);

        //获取当前用户信息(UserDetails子类) (登录成功了)
        HxzyUser  hxzyUser= (HxzyUser) authenticate.getPrincipal();

        // 生成令牌
        String token = UUID.randomUUID().toString();
        hxzyUser.setToken(token);

        //定义redis的key
        String redisKey= TZXMConst.LOGIN_TOKEN_KEY+token;

        //把token转为jwt
        Map<String,Object> data=new HashMap<>();
        data.put(TZXMConst.LOGIN_USER_KEY,token);
        String jwtToken = JWTUtil.createToken(data, jwtPwd.getBytes(StandardCharsets.UTF_8));

        //存储到redis中
        hxzyUser.setBeginDate(System.currentTimeMillis());
        //结束时间
        hxzyUser.setEndDate(System.currentTimeMillis()+ tokenExpired*60L*1000 );

        this.redisTemplate.opsForValue().set(redisKey,hxzyUser,tokenExpired, TimeUnit.MINUTES);

        return R.success(jwtToken);
    }

    /**
     * 登录方法原始的方法，案例用
     *
     * @param loginDTO 登录信息
     * @return 结果
     */
    public R loginDemo(@RequestBody @Valid LoginDTO loginDTO)
    {
        //模拟数据库查询登录成功
        SysUser user=new SysUser();
        user.setId(1L);
        user.setDeptId(103L);
        user.setPostId(1L);
        user.setName("管理员");
        user.setPhone("15888888888");
        user.setStatus("0");
        user.setSex("0");

        // 生成令牌
        String token = UUID.randomUUID().toString();

        //自定义对象
        HxzyUser  hxzyUser=new HxzyUser();
        hxzyUser.setSysUser(user);
        hxzyUser.setToken(token);

        //定义redis的key
        String redisKey= TZXMConst.LOGIN_TOKEN_KEY+token;

        //把token转为jwt
        Map<String,Object> data=new HashMap<>();
        data.put(TZXMConst.LOGIN_USER_KEY,token);
        String jwtToken = JWTUtil.createToken(data, jwtPwd.getBytes(StandardCharsets.UTF_8));

        //存储到redis中
        this.redisTemplate.opsForValue().set(redisKey,hxzyUser,tokenExpired, TimeUnit.MINUTES);

        return R.success(jwtToken);
    }

    /**
     * 获取用户信息
     *
     * @return 用户信息
     */
    @GetMapping("getInfo")
    public R getInfo() {
        HxzyUser hxzyUser= (HxzyUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        Map<String,Object> data =new HashMap<>();
        data.put("user", hxzyUser.getSysUser());
        data.put("roles", hxzyUser.getRoles());
        data.put("permissions", hxzyUser.getPermission());
        return R.success(data);
    }

    /**
     * 获取路由使用
     * @return
     */
    @ApiOperation(value = "获取路由菜单")
    @GetMapping(value = "/getRouters")
    public R router(){
        HxzyUser hxzyUser= (HxzyUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        List<MenuVO> menuVOList = this.sysMenuService.selectMenuTreeByUserId(hxzyUser);

        List<RouterVo> routerVoList =buildVueRouterUtil.buildMenus(menuVOList);
        return R.success(routerVoList);
    }

}
